package nancal.mp.mvc.dev2


import ch.qos.logback.classic.db.names.TableName
import io.swagger.annotations.Api
import io.swagger.annotations.ApiParam
import nancal.mp.db.mongo.mor
import nbcp.base.annotation.*
import nbcp.base.comm.*
import nbcp.base.extend.*
import nbcp.base.json.*
import nbcp.base.utils.StringUtil
import nbcp.mvc.sys.setDownloadFileName
import nbcp.myoql.db.db
import nbcp.myoql.db.es.RestClientScope
import nbcp.myoql.db.es.base.EsColumnName
import nbcp.myoql.db.es.component.*
import nbcp.myoql.db.es.extend.getAllAliasIndexes
import nbcp.myoql.db.es.extend.httpGet
import nbcp.myoql.db.mongo.*
import nbcp.myoql.db.mongo.base.MongoColumnName
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
import javax.servlet.http.HttpServletResponse

/**
 * Created by CodeGenerator at 2021-04-11 23:42:19
 */
@Api(description = "数据连接", tags = arrayOf("DbConnection"))
@RestController
@RequestMapping("/dev/es")
class EsToolController {
    @PostMapping("/get-mapping/{id}/{index}")
    fun getMapping(@PathVariable id: String, @PathVariable index: String): ApiResult<String> {
        var conn = mor.dev.esConnection.query()
            .linkOr({ it.id mongoEquals id }, { it.code mongoEquals id })
            .toEntity()
            .must().elseThrow { "找不到数据库连接" }

        var client = db.es.getRestClient(conn.connectionUri);
        var mapping = client.httpGet("/${index}/_mapping");
        return ApiResult.of(mapping);
    }

    @RequestMapping("/group-tables/{id}", method = arrayOf(RequestMethod.GET, RequestMethod.POST))
    fun tables(
        id: String
    ): ApiResult<Map<String, List<String>>> {
        var conn = mor.dev.esConnection.query()
            .linkOr({ it.id mongoEquals id }, { it.code mongoEquals id })
            .toEntity()
            .must().elseThrow { "找不到数据库连接" }

        //从中识别用户名密码.
        var client = db.es.getRestClient(conn.connectionUri);

        var list = client.getAllAliasIndexes();
        var data = list.groupBy { StringUtil.getUnderlineCase(it).split("_").first() }
        return ApiResult.of(data);
    }


    data class WhereExpression(
        var column: String = "",
        var op: String = "",
        var value: String = ""
    )


    @PostMapping("/get-data/{id}")
    fun viewEs(
        id: String,
        @Require table: String,
        @ApiParam("type=esql|user")
        type: String,
        wheres: List<WhereExpression>,
        sort: String,
        sortAsc: Boolean?,
        esql: String,
        @org.springframework.web.bind.annotation.RequestBody query: PagerModel<Any?>,
        response: HttpServletResponse
    ): ListResult<JsonMap> {
        var conn = mor.dev.esConnection.query()
            .linkOr({ it.id mongoEquals id }, { it.code mongoEquals id })
            .toEntity()
            .must().elseThrow { "找不到数据库连接" }

        query.take = Math.min(query.take, 25)
        return getData(conn.connectionUri, table, wheres, sort, sortAsc ?: false, esql, type, query)
    }


    fun getData(
        @Require connectionUri: String,
        @Require table: String,
        wheres: List<WhereExpression>,
        sort: String,
        sortAsc: Boolean,
        esql: String,
        type: String,
        queryModel: PagerModel<Any?>
    ): ListResult<JsonMap> {

        usingScope(RestClientScope(db.es.getRestClient(connectionUri))) {

            if (type == "esql") {
                var sql = esql

                if (!sql.startsWith("row ", true) && !sql.startsWith("from ", true)) {
                    sql = """From ${table} 
${esql}
"""
                }


                var isFrom = sql.startsWith("from ", true);
                var querySql = sql;

                if (isFrom) {
                    if (queryModel.take > 0 && !querySql.contains(" limit ")) {
                        querySql += " | limit ${queryModel.take}"
                    }
                }

                var query = EsqlRawQueryClip(table);

                var list = query.toList(querySql, JsonMap::class.java);

//                var count = query.toScalar(
//                    sql + """
//| stats total = count(*)
//""", Long::class.java
//                ) ?: 0;

                return ListResult.of<JsonMap>(list);

            }


            var query = EsQueryClipBase(table);

            wheres.forEach { where ->
                if (where.column.isNullOrEmpty()) {
                    return@forEach
                }

                if (where.op == "=") {
                    query.addFilter(EsColumnName(where.column) term where.value)
                } else if (where.op == "match") {
                    query.addFilter(EsColumnName(where.column) match where.value)
                } else if (where.op == ">") {
                    query.addFilter(EsColumnName(where.column) greaterThan where.value)
                } else if (where.op == ">=") {
                    query.addFilter(
                        EsColumnName(where.column)
                                greaterThanEquals
                                where.value
                    )
                } else if (where.op == "<") {
                    query.addFilter(EsColumnName(where.column) lessThan where.value)
                } else if (where.op == "<=") {
                    query.addFilter(
                        EsColumnName(where.column)
                                lessThanEquals
                                where.value

                    )
                } else if (where.op == "!=") {
                    query.addMustNot(EsColumnName(where.column) term where.value)
                } else if (where.op == "like") {
                    query.addFilter(EsColumnName(where.column) esLike where.value)
                }

            }

            if (sort.HasValue) {
                if (sortAsc) {
                    query.setOrderByAsc(EsColumnName(sort))
                } else {
                    query.setOrderByDesc(EsColumnName(sort))
                }
            }

            query.search.from = queryModel.skip;
            query.search.size = queryModel.take


            return query.toMapListResult();
        }
    }

    @PostMapping("/export/{id}")
    fun exportEs(
        id: String,
        @Require table: String,
        wheres: List<WhereExpression>,
        sort: String,
        sortAsc: Boolean?,
        esql: String,
        type: String,
        @org.springframework.web.bind.annotation.RequestBody query: PagerModel<Any?>,
        response: HttpServletResponse
    ) {
        var conn = mor.dev.esConnection.query()
            .linkOr({ it.id mongoEquals id }, { it.code mongoEquals id })
            .toEntity()
            .must().elseThrow { "找不到数据库连接" }

        var result = getData(conn.connectionUri, table, wheres, sort, sortAsc ?: false, esql, type, query);

        var content = result.data.map { it.ToJson() }.joinToString("\n")

        response.setDownloadFileName(table + ".dat");
        response.outputStream.write(content.toByteArray())

    }


    @PostMapping("/import/{id}")
    fun importMongo(
        file: MultipartFile,
        id: String
    ): ApiResult<JsonMap> {

        var conn = mor.dev.esConnection.query()
            .linkOr({ it.id mongoEquals id }, { it.code mongoEquals id })
            .toEntity()
            .must().elseThrow { "找不到数据库连接" }

        var fileName = file.originalFilename;
        if (!fileName.endsWith(".dat")) {
            return ApiResult.error("必须是 .dat 结尾")
        }

        var lines = file.inputStream.readContentString()
            .split("\n")
            .filter { it.HasValue }
            .map { it.FromJson<MongoDynamicEntity>()!! }

        if (lines.any() == false) {
            return ApiResult.error("找不到数据")
        }

        var count = 0;
        var errorCount = 0;

        var tableName = fileName.Slice(0, -4);


        var tableResult = tables(id);
        if (tableResult.hasError) {
            return ApiResult.error(tableResult.msg)
        }
        if (tableResult.data == null) {
            return ApiResult.error("找不到表")
        }

        if (!tableResult.data!!.values!!.Unwind().contains(tableName)) {
            return ApiResult.error("找不到表: " + tableName)
        }

        usingScope(RestClientScope(db.es.getRestClient(conn.connectionUri))) {

            var insert = EsBaseBulkInsertClip(tableName);

            lines.forEach { row ->
                count++;

                var id = row.getStringValue("id").AsString();
                if (id.isNullOrEmpty()) {
                    insert.addEntity(row);
                    return@forEach;
                }

                var needInsert = false;

                var query = EsQueryClipBase(tableName);
                query.whereId(id)
                if (query.exists()) {
                    var update = EsBaseBulkUpdateClip(tableName);
                    update.addEntity(row);
                    if (update.exec() == 0) {
                        needInsert = true;
                    }

                } else {
                    needInsert = true
                }

                if (needInsert) {
                    insert.addEntity(row);


                }

            }

            insert.exec();
            errorCount += (insert.entities.size - db.affectRowCount)
        }


        return ApiResult.of(JsonMap("count" to count, "errorCount" to errorCount))
    }

    @PostMapping("/delete-id/{connId}")
    fun deleteId(
        connId: String,
        @Require table: String,
        @Require rowId: String
    ): JsonResult {
        var conn = mor.dev.esConnection.queryById(connId).toEntity().must().elseThrow { "找不到数据库连接" }
        usingScope(RestClientScope(db.es.getRestClient(conn.connectionUri))) {

            var delete = EsBaseBulkDeleteClip(table);
            delete.addId(rowId)
            delete.exec();
        }

        return JsonResult();
    }
}